Game Development Path

Hitting that run button - what happens when you run the game

In the first few guides, you will have come across the concept of doing something continuously. In particular, we made use of this to implement jumping and falling gradually. For both of these, the relevant function to change was run in GameManager.java.

This function is called the game loop.

To see better what this means, let’s start at the beginning, by looking at what happens when you launch the game.

In java, when you run a project, it looks for a main class with a public static void main(String[] args) method. For this project, the main class is called.. Surprise suprise - Main.java!

Open it up and take a look at this miniature class. It looks like this:

public class Main {
    public static void main(String[] args) {
        // Initialise all the game components and start playing
        GamePanel gamePanel = new GamePanel();
        GameFrame gameFrame = new GameFrame(gamePanel);
        GameManager gameManager = new GameManager(gamePanel, gameFrame);

        gameManager.start();
    }
}

What do the lines here mean? Well, we first create a new instance of a GamePanel. First of all - what is a panel? This is a User Interface (UI) element in the Java Swing library.

Java Swing is a graphics library that has various UI components to help design programs with interfaces other than the console window. A JPanel, or informally, a panel in this library is essentially a container for other elements.

The game panel contains all the other UI components inside it - it doesn’t draw any graphics of its own.

Next, we create a new instance of a GameFrame. A frame, or in Java Swing terms - a JFrame, is basically a window. The frame is responsible for drawing the window controls (like minimise or close) and a frame around a panel.

In this case the GameFrame is a window that contains the GamePanel (and that’s why its constructor takes gamePanel as an argument).

Then we create a new instance of a GameManager. This class is not part of any library and is not a UI component. The GameManager has all the logic for handling input and redrawing the GamePanel when needed.

Finally, we call GameManager’s start function. If you look inside GameManager.java however, you will not find the definition of this function. How mysterious… ( ͜。 ͡ʖ ͜。)✧

The trick is in noticing that public class GameManager extends Thread.

You won’t need a needle for this - about threads in Java

Needle and thread -small

So what is this Thread class that GameManager extends? First, we should cover the concept of a process.

A program can have one or more processes, you can think of them as trains of thought. When a program has only one process, it can only do one thing at a time. Most console programs run on only one process - such a program might output some text, wait for user input, then do some calculations and produce some output.

What if this game ran with a single process? At first thought, that wouldn’t be so bad - you press a key, the character moves, then the game waits for you to press a key again. But what if we want to do two things at once, for example jump while moving right? Well, the program here would receive whichever key the user pressed first, then either jump or move right and then process the other key press… It gets even more complicated if we want to have other moving objects or creatures in the game - we could either wait for user input or animate those things, but not both at the same time.

Pretty much all applications with graphical interfaces will need to be able to multitask. And so, we will need multiple processes.

A thread is a kind of sub-process, that can be used to achieve the same outcome with better performance. Our GameManager class is such a thread.

It must implement the function run, which gets executed after the thread’s start function is called.

So, the line gameManager.start() actually ends up calling gameManager’s run function.

To be fair, we could spend the whole day talking about threading and still only scratch the surface. That’s not really what these game framework guides are for. We have discussed what threads are very briefly, but if you’re keen for more discussion, here are some further reading suggestions:

Fiddling with the construct of time - understanding the game loop

Now that we’ve walked through from the launch of the game program to the start of the game loop, let’s take a closer look at this amazing contraption. The game loop code should look like this:

@Override
public void run() {
    while (gameIsRunning) {
        if (!paused) {
            if (boy.outOfBounds()) {
                try {
                    currentLevel++;
                    world.loadLevel(currentLevel);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                boy.resetPosition();
            }

            boy.handleFalling();
            boy.handleJumping();
            boy.checkRestoringCount();
            gameIsRunning = boy.isAlive();
        }

        manageKeys();

        gamePanel.repaintGame();

        try {
            Thread.sleep(MAIN_SLEEP_TIME);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    gameFrame.dispatchEvent(new WindowEvent(gameFrame, WindowEvent.WINDOW_CLOSING));
}

What does this do? Let’s walk through it step-by-step.

First, there is a loop conditioned on whether gameIsRunning is true. This is just a boolean variable that is set to true when the game is launched and gets set to false when it should close.

Then there is a check for whether paused is false. Intuitively, it makes sense that the game can be paused or not. If you look ahead into the manageKeys function, you will see that the state of paused is toggled whenever ‘P’ is pressed.

So, if the game is not paused, the next few lines get executed. First we check if the character is outside the bounds of the current level. For more details, look up the outOfBounds function inside Boy.java

If that is the case, the next level is loaded.

Then we handle falling and jumping, which we already looked at in the previous guide.

checkRestoringCount is a method that makes the character blink 3 times if they recently died and just respawned.

Then, gameIsRunning is set to false if the character has died, otherwise it is unchanged.

After all this, the next few lines get executed regardless of whether the game is paused or not. manageKeys gets called, which handles user input. This definitely needs to be called even when the game is paused, otherwise - how will the user ever un-pause the game?

Then the game panel’s repaintGame function is called, which further down the chain causes all the other game elements to get redrawn. This needs to be done to reflect changes, such as the character having moved.

Finally, the game loop “sleeps” (pauses execution) for MAIN_SLEEP_TIME milliseconds. This is just an arbitrary constant defined at the top of GameManager. Its default value of 16 comes from this calculation:

If the game loop runs once every 16 milliseconds, it will run 1/16*1000 = 62.5 times every second. This is roughly equal to 60 times a second, which you might have seen being called 60FPS in some contexts. FPS stands for Frames Per Second, which is how many times a second the screen is updated (repainted). Higher values mean there is less of a delay between an action such as moving occurring and seeing the result on the screen. However, if you redraw the screen too often, the computer’s hardware may not be able to keep up.

All in all, this number is quite arbitrary - try changing its value and see what happens!

Implementing a game loop with a constant sleep time like this is called a constant timestep.

There are better ways to do this, but it can get very involved. If you feel adventurous, read through this amazing article and see if you can implement some of its advice:

Glenn Fiedler’s Fix Your Timestep article

Finally, the last line gets called after we get out of the loop that runs while gameIsRunning is true. It dispatches a JFrame event that closes the game window.

Level up! First advanced guide complete

Level Up!

Congratulations! You have completed the first advanced guide in the game development pathway. I hope that you now have a good idea of what the game loop is and what it does. Perhaps you even gathered some ideas for how to improve it.

The next guide will get back to a topic that we skimmed over previously - the character’s bounding box. We will be exploring how collision detection works in the game. Go forth through the portal into this adventure.

Be brave! We all believe you can do it.

Portal to the next guide